local LibItemInfo = LibStub:GetLibrary("LibItemInfo.7000")
local allPlayers = {}
local allSpecID = {}
local allXs = {} -- 像素图集

local aysOk = true
local current = 1 -- 显示像素点索引
local lie = 35 -- 列
local hang = 30 -- 行
local boss = { -- 要监听击杀、死亡状态提醒的BOSS
	["磨轮号"] = true,
	["弗莱兰多"] = true,
	["托克"] = true,
	["里克·混响"] = true,
	["斯提克斯·堆渣"] = true,
	["链齿狂人洛肯斯多"] = true,
	["独臂盗匪"] = true,
	["穆格·兹伊"] = true,
	["铬武大王加里维克斯"] = true
}

local twoBoss = {
	["弗莱兰多"] = 1,
	["托克"] = 1
}

local spcBoss_1 = "弗莱兰多"
local spcBoss_2 = "托克"

-- local twoBoss = {
-- 	["蛛魔散兵"] = 1,
-- 	["蛛魔织网者"] = 1
-- }

-- local spcBoss_1 = "蛛魔散兵"
-- local spcBoss_2 = "蛛魔织网者"

-- local combatBoss = "0"
local lastKilledBoss = "0"
local killingBossName = "0"

function table.contains(tbl, value)
    for _, v in ipairs(tbl) do
        if v == value then
            return true
        end
    end
    return false
end

-- 生成一个打乱后的5位数字
local function generate5DigitShuffledNumber(input, seed)
     -- 输入转为数字类型
        local num = tonumber(input)
        if not num then
            return "Invalid input"  -- 如果输入不是有效的数字
        end
    
        -- 设置一个随机的种子值，用于混淆计算
        -- local seed = 137  -- 你可以任意更改这个数值
    
        -- 基础混淆操作：加、减、乘、除等
        num = num + seed            -- 加上一个常数（增加不可预测性）
        num = num * 5               -- 乘以一个常数，放大数值
        num = num - (seed * 2)      -- 减去种子的一部分，增加混淆性
        num = num + 100000         -- 确保结果大于100000
    
        -- 使结果始终为5位数字
        num = num % 90000 + 10000  -- 保证结果在10000到99999之间
    
        -- 返回最终的5位数字
        return num
end

local function todayTime()
	local dateInfo = C_DateAndTime.GetCurrentCalendarTime()
	local year, month, day = dateInfo.year, dateInfo.month, dateInfo.monthDay
	-- 获取年份后两位，并在前面补 0
	local shortYear = string.sub(tostring(year), -1)
	-- 确保 month 和 day 始终是两位数格式
	local monthStr = string.format("%02d", month)
	local dayStr = string.format("%02d", day)
	-- 拼接成字符串
	local dateStr = shortYear .. monthStr .. dayStr
	-- 转换为数字
	return tonumber(dateStr)
end

local joinKey = generate5DigitShuffledNumber(todayTime(), 999) -- 加入队伍的随机密码

-- print(joinKey)

local function GetPhysicalToLogicalScale()
    -- 获取物理屏幕分辨率
    local screenWidth, screenHeight = GetPhysicalScreenSize()
    
    -- 获取当前逻辑分辨率（受窗口模式/全屏影响）
    local logicalWidth, logicalHeight = GetScreenWidth(), GetScreenHeight()
    
    -- 计算实际缩放比例（物理像素/逻辑像素）
    return screenWidth / logicalWidth
end
	
local targetPhysicalSize = 1
	
-- 创建像素图
local function createDRCodeMap()
	local scale = GetPhysicalToLogicalScale()
	local w = targetPhysicalSize / scale
	local index = 1
	for j = 1, lie do
	    for i = 1, hang do
	        local xs1 = CreateFrame("Frame", "xs"..index, UIParent)
			
	        xs1:SetPoint("TOPLEFT", (i - 1) * w, (0 - j + 1) * w - 1)
	        xs1:SetSize(w, w)
			-- xs1:SetScale(1)
			-- xs1:SetIgnoreParentScale(true)
			xs1.bg = xs1:CreateTexture(nil, "BACKGROUND")
			xs1.bg:SetAllPoints(xs1)  -- 设置背景填满整个框架
			xs1.bg:SetColorTexture(1, 1, 1)
			allXs[index] = xs1
			-- if (index == 1) then
			-- 	xs1:RegisterEvent("DISPLAY_SIZE_CHANGED")
			-- 	xs1:RegisterEvent("UI_SCALE_CHANGED")
			-- 	xs1:RegisterEvent("PLAYER_ENTERING_WORLD")
			-- 	xs1:SetScript("OnEvent", UpdateSize)
			-- end
			index = index + 1
			
	    end
	end
end

local function UpdateFrame()

	local scale = GetPhysicalToLogicalScale()
	local w = targetPhysicalSize / scale
	local index = 1
	for j = 1, lie do
	    for i = 1, hang do
	        local xs1 = allXs[index]
			xs1:SetPoint("TOPLEFT", (i - 1) * w, (0 - j + 1) * w - 1)
			xs1:SetSize(w, w)
			index = index + 1
	    end
	end
end

local checker = CreateFrame("Frame")
checker:SetScript("OnUpdate", function(self, elapsed)
    self.time = (self.time or 0) + elapsed
    if self.time > 0.5 then  -- 每 0.5 秒检查一次
        self.time = 0
        UpdateFrame()
    end
end)



local function utf8_codepoint(str)
    local byte1 = string.byte(str, 1)
    if byte1 <= 0x7F then
        -- Single byte (ASCII)
        return byte1
    elseif byte1 >= 0xC0 and byte1 <= 0xDF then
        -- Two bytes
        local byte2 = string.byte(str, 2)
        return (byte1 - 0xC0) * 0x40 + (byte2 - 0x80)
    elseif byte1 >= 0xE0 and byte1 <= 0xEF then
        -- Three bytes
        local byte2 = string.byte(str, 2)
        local byte3 = string.byte(str, 3)
        return (byte1 - 0xE0) * 0x1000 + (byte2 - 0x80) * 0x40 + (byte3 - 0x80)
    elseif byte1 >= 0xF0 and byte1 <= 0xF7 then
        -- Four bytes
        local byte2 = string.byte(str, 2)
        local byte3 = string.byte(str, 3)
        local byte4 = string.byte(str, 4)
        return (byte1 - 0xF0) * 0x40000 + (byte2 - 0x80) * 0x1000 + (byte3 - 0x80) * 0x40 + (byte4 - 0x80)
    end
end

-- 将单个字符转换为 RGB
function CharToRGB(char)
    local unicodeValue = utf8_codepoint(char) -- 获取 Unicode 码点
    local r = math.floor(unicodeValue / (256 * 256)) % 256 -- 高 8 位
    local g = math.floor(unicodeValue / 256) % 256         -- 中间 8 位
    local b = unicodeValue % 256                           -- 低 8 位
    return r, g, b
end

-- 计算 UTF-8 字符串的字符长度（支持中文和多字节字符）
function utf8_strlen(str)
    local length = 0
    local i = 1
    while i <= #str do
        local byte1 = string.byte(str, i)
        
        -- 判断当前字符是单字节字符还是多字节字符
        if byte1 >= 0xC0 then  -- 多字节字符的首字节大于等于 0xC0
			if  byte1 <= 0xDF then
				i = i + 2
			else
				i = i + 3  -- 跳过 3 个字节，表示一个多字节字符（通常是中文或其他字符）
			end
        else
            i = i + 1  -- 单字节字符（如英文字符），只需跳过 1 个字节
        end
        length = length + 1
    end
    return length
end

function is_two_byte_character(str, i)
    local byte1 = string.byte(str, i)
    local byte2 = string.byte(str, i + 1)

    -- 检查是否在 2 字节字符范围内
    if byte1 >= 0xC0 and byte1 <= 0xDF and byte2 >= 0x80 and byte2 <= 0xBF then
        return true
    else
        return false
    end
end

function utf8_sub(str, start, _end)
    local length = 0
    local i = 1
    local result = ""

    -- 计算起始位置和结束位置的字符位置
    while i <= #str do
		
        local byte1 = string.byte(str, i)
		-- 符·位置
        if byte1 >= 0xC0 then
            -- 多字节字符，判断是2字节字符（如·）还是3字节字符（如中文）
            if  byte1 <= 0xDF then
                -- 2字节字符 (如 ·) ·
                if length >= start and length < _end then
                    result = result .. str:sub(i, i + 1)  -- 截取 2 个字节
                end
                i = i + 2
            else 
                -- 3字节字符（如中文）
                if length >= start and length < _end then
                    result = result .. str:sub(i, i + 2)  -- 截取 3 个字节
                end
                i = i + 3
            end
        else
            -- 单字节字符（如英文字符）
            if length >= start and length < _end then
                result = result .. str:sub(i, i)
            end
            i = i + 1
        end
        
        length = length + 1
        
        -- 如果达到 _end 位置，停止截取
        if length >= _end then
            break
        end
    end

    return result
end



local function setColor(r, g, b)
    local xs = allXs[current]
    if (xs) then
    	-- xs:SetStatusBarColor(r / 255, g / 255, b / 255)
		xs.bg:SetColorTexture(r / 255, g / 255, b / 255)
		current = current + 1
    end
end

-- 汉字转换成颜色像素点
local function toRGBCode(str) 
	current = 1
	local stopLength = utf8_strlen(str) - 1
	for i = 0, (hang * lie - 1) do
		if (i <= stopLength) then
			local char = utf8_sub(str, i, i + 1)
			-- print(char)
			local cr, cg, cb = CharToRGB(char)
			setColor(cr, cg, cb)
		else
			setColor(255, 255, 255)
		end
	end
end

-- 异步版本颜色处理器
function asyncToRGBCode(str, callback)
	
    -- 预计算关键参数
    local totalSlots = hang * lie  -- 总显示槽位
    local strLength = utf8_strlen(str)
    local currentIndex = 0         -- 当前处理位置
    local resultBuffer = {}        -- 颜色结果缓存
    -- 分块处理器
    local function processChunk()
        local startTime = debugprofilestop()  -- 性能保护
        -- 每次处理10个字符（可根据实际情况调整）
        for _ = 1, 50 do
            if currentIndex >= totalSlots then
                break
            end
            -- 核心处理逻辑
            if currentIndex <= (strLength - 1) then
                local char = utf8_sub(str, currentIndex, currentIndex + 1)
                local cr, cg, cb = CharToRGB(char)
                resultBuffer[currentIndex + 1] = {cr, cg, cb}
            else
                resultBuffer[currentIndex + 1] = {255, 255, 255}  -- 白色填充
            end
            
            currentIndex = currentIndex + 1
			-- print(currentIndex)
            
            -- 单帧最大处理时间保护（2ms）
            if (debugprofilestop() - startTime) > 2 then
                break
            end
        end
        -- 进度判断
        if currentIndex >= totalSlots then
			current = 1
            -- 最终颜色设置
            for i, color in pairs(resultBuffer) do
                setColor(color[1], color[2], color[3])
            end
            if callback then callback() end
        else
            -- 下一帧继续
            C_Timer.After(0, processChunk)
        end
    end
    -- 启动处理
    processChunk()
end


local function getClassId(class)
    -- 定义职业名称到 ID 的映射表
    local classToId = {
        WARRIOR = 1,
        PALADIN = 2,
        HUNTER = 3,
        ROGUE = 4,
        PRIEST = 5,
        DEATHKNIGHT = 6,
        SHAMAN = 7,
        MAGE = 8,
        WARLOCK = 9,
        MONK = 'A',  -- 10 -> A
        DRUID = 'B',  -- 11 -> B
        DEMONHUNTER = 'C',  -- 12 -> C
        EVOKER = 'D',  -- 13 -> D
    }
    -- 返回映射表中的职业 ID
    return classToId[class] or 'Unknown'
end

local function isBoss(name)
    for _, v in ipairs(boss) do
        if v == name then
            return true
        end
    end
    return false
end

local frame = CreateFrame("Frame")
frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
frame:SetScript("OnEvent", function(self, event, ...)
	-- 判断玩家是否在地下城或团队副本中
	local inInstance, instanceType = IsInInstance()
	-- 输出副本状态和类型
	if inInstance then
	    if instanceType == "party" or instanceType == "raid" then
			local _,subevent,_,_,sourceName,_,_,_,destName = CombatLogGetCurrentEventInfo()
			-- 判断击杀事件
			if subevent == "UNIT_DIED" then
				if (boss[destName]) then
					-- print(destName.."死了")
					if (destName == spcBoss_1) then
						twoBoss[spcBoss_1] = 0
					end
					if (destName == spcBoss_2) then
						twoBoss[spcBoss_2] = 0
					end
					lastKilledBoss = destName
				end
			elseif subevent == "SPELL_DAMAGE" then
				if (boss[destName]) then
					-- print(sourceName.." 正在攻击 "..destName)
					killingBossName = destName
				end
			end
		end
	end
end)


local JOIN_IPM_F = CreateFrame("Frame", "JOIN_IPM_F", UIParent)
JOIN_IPM_F:RegisterEvent("CHAT_MSG_WHISPER")

JOIN_IPM_F:SetScript("OnEvent", function(_, _, a, b)

	if (tonumber(a) == tonumber(joinKey) and b ~= UnitName("player")) then 
	-- /run C_PartyInfo.InviteUnit('是谁关的灯-冰风岗')
		C_PartyInfo.InviteUnit(b)	
	end
end)


-- 获取专精名字
local function GetInspectSpecName(unit)
    local specID, specName
    if (UnitIsUnit(unit, "player")) then
        specID = GetSpecialization()
        specName = select(2, GetSpecializationInfo(specID))
    else
        specID = GetInspectSpecialization(unit)
        if (specID and specID > 0) then
            specName = select(2, GetSpecializationInfoByID(specID))
        end
    end
    return specName or ""
end

-- 获取专精ID
local function GetInspectSpecID(unit)
    local specID
    if (UnitIsUnit(unit, "player")) then
		local specIndex = GetSpecialization()
        specID = GetSpecializationInfo(specIndex)
    else
        specID = GetInspectSpecialization(unit)
    end
    return specID or ""
end

-- 获取平均装等(有缓存) 因 LibItemInfo:GetUnitItemLevel 有严重性能问题，所以将其废弃，固定返回 0
local function GetItemLev(name, unit)
	local un = unit
	if (UnitIsUnit(unit, "player")) then
		un = "player"
	end
	local itemLev = allPlayers[name]
	local currentLev = select(2, LibItemInfo:GetUnitItemLevel(un)) -- 此函数存在性能问题，调用会非常卡，废弃他
	if (currentLev ~= 0) then
		allPlayers[name] = currentLev
		itemLev = currentLev
	end
	return itemLev or 0
	-- return 0
end

-- 获取专精ID(有缓存)
local function GetSpecID(name, unit)

	local un = unit
	if (UnitIsUnit(unit, "player")) then
		un = "player"
	end
	
	local spId = allSpecID[name]
	local SpecID = GetInspectSpecID(un)
	if (SpecID ~= 0) then
		allSpecID[name] = SpecID
		spId = SpecID
	end
	
	return spId or 0
end

-- 根据专精ID获取专精名字
local function GetSpecName(specID)
    local specName = select(2, GetSpecializationInfoByID(specID))
    -- if (UnitIsUnit(unit, "player")) then
    --     specName = select(2, GetSpecializationInfo(specID))
    -- else
    --     if (specID and specID > 0) then
    --         specName = select(2, GetSpecializationInfoByID(specID))
    --     end
    -- end
    return specName or "0"
end

-- 事件处理函数COD码生成
local function OnPartyMemberChanged()

	-- 是否在战斗中
	local isCombat = false
	local str = ""
	-- 当前玩家所在服务器
	local playerRealm = GetRealmName()
	-- 判断是否在团队副本中
	local cjPlayerName
	if (not IsInRaid()) then
		local playerName = GetUnitName("player")
		
		local _, playerClass = UnitClass("player")
		local mapClass = getClassId(playerClass)
		if (mapClass == "Unknown") then
			-- print('Unknown')
			return
		end
		
		-- local playerRole = UnitGroupRolesAssigned("player")
		-- str = getClassId(playerClass)..playerName..utf8_sub(playerRole, 0, 1).."10"
		
		--- 特殊号 1:进组宏且是队长 2:仅进组宏号 3:仅是队长
		-- 阵营:专精:角色名字:服务器:平均装等:队伍:特殊号:在线:职业
		cjPlayerName = playerName
		local functi = select(2, UnitFactionGroup("player"))
		local specID = GetSpecID(playerName, "player")
		local specName = GetSpecName(specID)
		str = functi..":"..specName..":"..playerName..":"..playerRealm..":"..math.floor(GetItemLev(playerName, "player"))..":1:1:1:"..mapClass
		isCombat = UnitAffectingCombat("player")
	end

	-- 获取当前队伍/团队成员数量
	local numMembers = GetNumGroupMembers()

	for i = 1, numMembers do
		-- 获取队伍/团队成员的单元名（party1, party2... 或 raid1, raid2...）
		local unit = IsInRaid() and "raid" .. i or "party" .. i
	
		if (UnitExists(unit)) then

			-- 获取当前成员的角色（坦克、治疗或输出）
			-- local role = UnitGroupRolesAssigned(unit)
			-- 输出该成员的角色定位
			-- local name = string.gsub(GetUnitName(unit), "%b()", "")  -- 获取成员的名称
			if (not isCombat) then
				isCombat = UnitAffectingCombat(unit)
			end
			local name, realm = UnitName(unit)
			if (not realm) then
				realm = playerRealm
			end
			-- 判断当前成员是否在团队中（如果不在团队中，下面获取小队及顺序相关逻辑意义不大，这里简单跳过这部分）
			local gIndex = 1
			local unUse = 0
			local leader = false
			if IsInRaid() then
				-- 获取成员所在的小队编号，返回值为1到8（通常情况，对应8个小队）
				local _,rank,subgroupIndex,_,_,_,_,_,_,mark = GetRaidRosterInfo(i)
				gIndex = subgroupIndex
				
				-- print(GetRaidRosterInfo(i))
				if (mark and mark == 'MAINASSIST') then
					unUse = 1
				end
				if (rank == 2) then
					leader = true
				end
				-- 计算成员在小队内的顺序（位置序号）
				-- local positionInSubgroup = ((i - 1) % 5) + 1
				-- print(name.. " 在第 ".. subgroup.. " 小队，小队内顺序是第 ".. positionInSubgroup.. " 个")
			end

			-- 职业
			local _, class = UnitClass(unit)
			local classID = getClassId(class)
			if (classID == "Unknown") then
				-- print('Unknown')
				return
			end
			--- 特殊号 1:进组宏且是队长 2:仅进组宏号 3:仅是队长
			-- 阵营:专精:角色名字:服务器:平均装等:队伍:特殊号:在线:职业
			local functi = select(2, UnitFactionGroup(unit))
			local specID = GetSpecID(name, unit)
			local specName = GetSpecName(specID)
			if utf8_strlen(str) == 0 then
				str = functi..":"..specName..":"..name..":"..realm..":"..math.floor(GetItemLev(name, unit))
			else
				str = str..","..functi..":"..specName..":"..name..":"..realm..":"..math.floor(GetItemLev(name, unit))
			end
			
			-- 判断这个角色是否是当前角色 采集角色名字显示
			if (UnitIsUnit(unit, "player")) then
				cjPlayerName = name
			end
			-- 如果这个角色是队长
			if (leader) then
				if (unUse == 1) then
					-- 进组宏号
					str = str..":"..gIndex..":1"
				else
					str = str..":"..gIndex..":3"
				end
			else
				if (unUse == 1) then
					-- 仅进组宏号
					str = str..":"..gIndex..":2"
				else
					str = str..":"..gIndex..":0"
				end
			end
			
			if (UnitIsConnected(unit)) then
				str = str..":1:"..classID
			else
				str = str..":0:"..classID
			end
			
		end
	end
	-- local killing = "0" 
	if (isCombat) then

		-- 阵营:专精:角色名字:服务器:平均装等:队伍:特殊号:在线:职业#当前插件角色:是否在击杀boss:正在击杀的Boss名字:最后一次击杀掉的boss:当前队伍是否在战斗中
		
		-- print('战斗中')
		-- killing = "1"
	else
		-- combatBoss = "0"
		killingBossName = "0"
		-- print('脱离战斗')
		-- 脱战后，如果最后击杀boss是 狂龙弗莱兰多 或者 风暴巨猩托克
		-- 需要判断是否两个都死掉了，才能算作真的死亡
		if (lastKilledBoss == spcBoss_1 or lastKilledBoss == spcBoss_2) then
			if (twoBoss[spcBoss_1] == 1 or twoBoss[spcBoss_2] == 1) then
				-- 重置成未死亡
				twoBoss[spcBoss_1] = 1
				twoBoss[spcBoss_2] = 1
				lastKilledBoss = "0"
				print('没有死透')
			end
		end
	end
	-- 阵营:专精:角色名字:服务器:平均装等:队伍:特殊号:在线:职业#当前插件角色:是否在击杀boss:正在击杀的Boss名字:最后一次击杀掉的boss
	str = str.."#"..cjPlayerName..":"..killingBossName..":"..lastKilledBoss
	-- toRGBCode(str)
	-- 使用示例（替换原有同步调用）
	if (aysOk) then
		aysOk = false
		asyncToRGBCode(str, function()
			aysOk = true
		end)
	end
end

createDRCodeMap()
C_Timer.NewTicker(1, OnPartyMemberChanged)


-- 这里改你想要的字符串内容
-- local str = "123456789abcdefg"
-- toRGBCode(str)














